package com.tubeonfire.service;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;

import javax.cache.Cache;
import javax.cache.CacheException;
import javax.cache.CacheManager;

import com.google.gdata.client.youtube.YouTubeQuery;
import com.google.gdata.client.youtube.YouTubeService;
import com.google.gdata.data.youtube.UserProfileEntry;
import com.google.gdata.data.youtube.VideoEntry;
import com.google.gdata.data.youtube.VideoFeed;
import com.google.gdata.util.ServiceException;
import com.google.gdata.util.ServiceForbiddenException;
import com.tubeonfire.entity.Author;
import com.tubeonfire.entity.Tube;
import com.tubeonfire.util.StringHelper;

public class YoutubeService {

	private int limit = 12;
	private static YouTubeService service = new YouTubeService(
			"tubeilike",
			"AI39si4hdZVHF2A5UZmnr1yRZ3mWhwQ9lIqfBggC66zeM3qdfUB1DYAdckeqd6IB24-1WGeCZRKh5KruMxYF9cmcBdq9ymU6IQ");
	private int page = 1;
	private int totalResult = 0;
	private int totalPage = 0;
	private boolean isCache = false;
	private List<Tube> listResult = new ArrayList<Tube>();
	private Tube currentTube = new Tube();
	public static Cache cache = null;
	private static String cachePrefix = "YoutubeService_";
	public static boolean startedCache = false;
	private static final Logger log = Logger.getLogger(YoutubeService.class
			.getName());
	private static boolean tooManyRecentCallError = false;

	public static Cache getCache() {
		return cache;
	}

	public static boolean isStartedCache() {
		return startedCache;
	}

	public boolean isCache() {
		return isCache;
	}

	public void setCache(boolean isCache) {
		this.isCache = isCache;
	}

	public Tube getCurrentTube() {
		return currentTube;
	}

	public void setCurrentTube(Tube currentTube) {
		this.currentTube = currentTube;
	}

	public static void setTooManyRecentCallError(boolean tooManyRecentCallError) {
		YoutubeService.tooManyRecentCallError = tooManyRecentCallError;
	}

	public boolean isTooManyRecentCallError() {
		return tooManyRecentCallError;
	}

	public void setLimit(int limit) {
		this.limit = limit;
	}

	public int getTotalPage() {
		totalPage = totalResult / limit;
		if ((totalResult % limit) > 0) {
			totalPage += 1;
		}
		return totalPage;
	}

	public int getLimit() {
		return limit;
	}

	public int getPage() {
		return page;
	}

	public void setPage(int page) {
		this.page = page;
	}

	public int getTotalResult() {
		return totalResult;
	}

	public void setTotalResult(int totalResult) {
		this.totalResult = totalResult;
	}

	public List<Tube> getListResult() {
		return listResult;
	}

	public void setListResult(List<Tube> listResult) {
		this.listResult = listResult;
	}

	public static void initCache() {
		if (cache == null || !startedCache) {
			try {
				cache = CacheManager.getInstance().getCacheFactory()
						.createCache(Collections.emptyMap());
				startedCache = true;
			} catch (CacheException e) {
				log.warning(e.toString());
				e.printStackTrace();
			}
		}
	}

	@SuppressWarnings("unchecked")
	public void searchByChannel(String channel, boolean all) {
		try {
			System.out.println("Searching videos from Youtube Channel...");
			String prefix = cachePrefix + "channel_" + channel + page;
			int start = (page - 1);
			if (start < 0) {
				start = 0;
			}
			if (cache != null && cache.containsKey(prefix) && !all) {
				listResult = (List<Tube>) cache.get(prefix);
				page = (Integer) cache.get(prefix + "page");
				totalPage = (Integer) cache.get(prefix + "totalPage");
				totalResult = (Integer) cache.get(prefix + "totalResult");
				System.out.println("Getting video from cache...");
			} else {
				if (start < 0) {
					start = 0;
				}
				listResult = new ArrayList<Tube>();
				String feedUrl = "http://gdata.youtube.com/feeds/api/videos?max-results="
						+ limit
						+ "&start-index="
						+ ((start * limit) + 1)
						+ "&orderby=published" + "&author=" + channel;
				VideoFeed videoFeed = service.getFeed(new URL(feedUrl),
						VideoFeed.class);
				totalResult = videoFeed.getTotalResults();
				System.out.println("Found : " + totalResult);
				initCache();
				for (VideoEntry videoEntry : videoFeed.getEntries()) {
					Tube tube = new Tube();
					tube = videoEntryToTube(videoEntry);
					if (tube != null) {
						listResult.add(tube);
					}
				}
				System.out.println("Return : " + listResult.size());
				if (!all) {
					cache.put(prefix, listResult);
					cache.put(prefix + "page", page);
					cache.put(prefix + "totalPage", totalPage);
					cache.put(prefix + "totalResult", totalResult);
					System.out.println("Putting to cache success !");
				}
				tooManyRecentCallError = false;
			}
		} catch (MalformedURLException e) {
			log.warning(e.toString());
			e.printStackTrace();
		} catch (IOException e) {
			log.warning(e.toString());
			e.printStackTrace();
		} catch (ServiceForbiddenException e) {
			log.warning(e.toString());
			e.printStackTrace();
			tooManyRecentCallError = true;
		} catch (ServiceException e) {
			log.warning(e.toString());
			e.printStackTrace();
		} catch (Exception e) {
			log.warning(e.toString());
			e.printStackTrace();
		}
	}

	@SuppressWarnings("unchecked")
	public void searchByKey(String key, boolean hd) {
		try {
			System.out.println("Searching videos from Youtube...");
			String prefix = cachePrefix + "key_" + key + page + hd;
			System.out.println("search..." + prefix);
			int start = (page - 1);
			if (start < 0) {
				start = 0;
			}
			if (cache != null && cache.containsKey(prefix)) {
				listResult = (List<Tube>) cache.get(prefix);
				page = (Integer) cache.get(prefix + "page");
				totalPage = (Integer) cache.get(prefix + "totalPage");
				totalResult = (Integer) cache.get(prefix + "totalResult");
				isCache = true;
				System.out.println("Getting video from cache...");
			} else {
				listResult = new ArrayList<Tube>();
				YouTubeQuery query = new YouTubeQuery(new URL(
						"https://gdata.youtube.com/feeds/api/videos"));
				query.setFullTextQuery(key);
				query.setMaxResults(limit);
				query.setStartIndex(limit * start + 1);
				query.setSafeSearch(YouTubeQuery.SafeSearch.NONE);
				if (hd) {
					query.setStringCustomParameter("hd", "true");
				}
				VideoFeed videoFeed = service.query(query, VideoFeed.class);
				totalResult = videoFeed.getTotalResults();
				System.out.println("Found : " + totalResult);
				initCache();
				for (VideoEntry videoEntry : videoFeed.getEntries()) {
					Tube tube = videoEntryToTube(videoEntry);
					if (tube != null) {
						listResult.add(tube);
					}
				}
				System.out.println("Return : " + listResult.size());
				cache.put(prefix, listResult);
				cache.put(prefix + "page", page);
				cache.put(prefix + "totalPage", totalPage);
				cache.put(prefix + "totalResult", totalResult);
				System.out.println("Putting to cache success !");
				tooManyRecentCallError = false;
				isCache = false;
			}
		} catch (MalformedURLException e) {
			log.warning(e.toString());
			e.printStackTrace();
		} catch (IOException e) {
			log.warning(e.toString());
			e.printStackTrace();
		} catch (ServiceForbiddenException e) {
			log.warning(e.toString());
			e.printStackTrace();
			tooManyRecentCallError = true;
		} catch (ServiceException e) {
			log.warning(e.toString());
			e.printStackTrace();
		} catch (Exception e) {
			log.warning(e.toString());
			e.printStackTrace();
		}
	}

	public void searchById(String id) {
		Tube tub = new Tube();
		try {
			String prefix = "tubeModel_" + "id_" + id;
			listResult = new ArrayList<Tube>();
			if (cache != null && cache.containsKey(prefix)) {
				tub = (Tube) cache.get(prefix);
				currentTube = tub;
				listResult.add(tub);
				page = 1;
				totalPage = 1;
				totalResult = 1;
			} else {
				System.out.println("Searching video from Youtube...");
				String videoEntryUrl = "http://gdata.youtube.com/feeds/api/videos/"
						+ id;
				VideoEntry videoEntry = service.getEntry(
						new URL(videoEntryUrl), VideoEntry.class);
				tub = videoEntryToTube(videoEntry);
				initCache();
				currentTube = tub;
				listResult.add(tub);
				page = 1;
				totalPage = 1;
				totalResult = 1;
				tooManyRecentCallError = false;
			}
		} catch (MalformedURLException e) {
			log.warning(e.toString());
			e.printStackTrace();
		} catch (IOException e) {
			log.warning(e.toString());
			e.printStackTrace();
		} catch (ServiceForbiddenException e) {
			log.warning(e.toString());
			e.printStackTrace();
			tooManyRecentCallError = true;
		} catch (ServiceException e) {
			log.warning(e.toString());
			e.printStackTrace();
		} catch (Exception e) {
			log.warning(e.toString());
			e.printStackTrace();
		}
	}

	public static Tube searchStaticById(String id) {
		Tube tub = new Tube();
		try {
			String prefix = "";
			prefix = cachePrefix + "id_" + id;
			if (cache != null && cache.containsKey(prefix)) {
				tub = (Tube) cache.get(prefix);
				System.out.println("Getting video from cache...");
			} else {
				System.out.println("Searching video from Youtube...");
				String videoEntryUrl = "http://gdata.youtube.com/feeds/api/videos/"
						+ id;
				VideoEntry videoEntry = service.getEntry(
						new URL(videoEntryUrl), VideoEntry.class);
				tub = videoEntryToTube(videoEntry);
				System.out.println("Putting to cache success !");
				tooManyRecentCallError = false;
			}
		} catch (MalformedURLException e) {
			log.warning(e.toString());
			e.printStackTrace();
			tub = null;
		} catch (IOException e) {
			log.warning(e.toString());
			e.printStackTrace();
			tub = null;
		} catch (ServiceForbiddenException e) {
			log.warning(e.toString());
			e.printStackTrace();
			tooManyRecentCallError = true;
			tub = null;
		} catch (ServiceException e) {
			log.warning(e.toString());
			e.printStackTrace();
			tub = null;
		} catch (Exception e) {
			log.warning(e.toString());
			e.printStackTrace();
			tub = null;
		}
		return tub;
	}

	public static boolean checkChannel(String channel) {
		boolean result = false;
		try {
			System.out.println("Checking channel...");
			String feedUrl = "http://gdata.youtube.com/feeds/api/videos?author="
					+ channel;
			VideoFeed feed = service.getFeed(new URL(feedUrl), VideoFeed.class);
			if (feed.getEntries().size() > 0) {
				result = true;
			}
		} catch (Exception e) {
			log.warning(e.toString());
			e.printStackTrace();
			result = false;
		}
		return result;
	}

	public static Author getUserProfile(Author author) {
		String profileUrl = author.getUri();
		UserProfileEntry profileEntry;
		try {
			profileEntry = service.getEntry(new URL(profileUrl),
					UserProfileEntry.class);
			author.setThumbnail(profileEntry.getThumbnail().getUrl());
			author.setUserId(profileEntry.getId());
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ServiceException e) {
			e.printStackTrace();
		}
		return author;
	}

	@SuppressWarnings("unchecked")
	public static Tube videoEntryToTube(VideoEntry entry) {
		Tube tube = new Tube();
		try {
			tube.setId(entry.getMediaGroup().getVideoId());
			if (entry.getMediaGroup().getThumbnails() != null
					&& entry.getMediaGroup().getThumbnails().size() > 1) {
				tube.setImageUrl(entry.getMediaGroup().getThumbnails().get(1)
						.getUrl());
			}
			tube.setTitle(entry.getMediaGroup().getTitle()
					.getPlainTextContent());
			if (entry.getMediaGroup().getDescription() != null) {
				tube.setDescription(entry.getMediaGroup().getDescription()
						.getPlainTextContent());
			}
			tube.setAlias(StringHelper.getAliasByLanguage(tube.getTitle()));
			tube.setAuthorUrl(entry.getAuthors().get(0).getUri());
			if (entry.getMediaGroup().getDuration() != null) {
				long duration = entry.getMediaGroup().getDuration();
				int hours = (int) (duration / 3600);
				int remainder = (int) (duration - hours * 3600);
				int minutes = remainder / 60;
				remainder = remainder - minutes * 60;
				int second = remainder;
				tube.setDuration(duration);
				tube.setTotalTime(((hours > 0) ? (hours + ":") : "")
						+ String.format("%02d", minutes) + ":"
						+ String.format("%02d", second));
			}
			if (entry.getMediaGroup().getCategories() != null
					&& entry.getMediaGroup().getCategories().size() > 0) {
				tube.setChannelId(StringHelper.replace(entry.getMediaGroup()
						.getCategories().get(0).getLabel()));
				tube.setChannelName(entry.getMediaGroup().getCategories()
						.get(0).getLabel());
			}

			tube.setPublished(new Date(entry.getPublished().getValue()));
			if (entry.getStatistics() != null) {
				tube.setYoutubeView(entry.getStatistics().getViewCount());
			}
			tube.setStatus(1);
			initCache();
			cache.put(cachePrefix + "id_" + tube.getId(), tube);
			return tube;
		} catch (Exception e) {
			log.warning(e.toString());
			e.printStackTrace();
			return null;
		}

	}
}
